package com.多用户通讯编程.QQ.Server.QQservice;

import com.多用户通讯编程.QQ.Common.Message;
import com.多用户通讯编程.QQ.Common.MessageType;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

@SuppressWarnings("all")
public class ServerConnectClientThread extends Thread {
    /// 跟客户端通讯的socket
    private Socket socket;
    /// 用户名
    private String UserId;
    /// 跟用户通讯的输入流
    ObjectInputStream ois = null;
    /// 跟用户通讯的输出流
    ObjectOutputStream oos = null;

    /**
     * @param socket 跟用户通讯的socket
     * @param userId 用户id
     * @param ois    跟用户通讯的输入流
     * @param oos    跟用户通讯的输出流
     */
    public ServerConnectClientThread(Socket socket, String userId, ObjectInputStream ois, ObjectOutputStream oos) {
        this.socket = socket;
        this.UserId = userId;
        this.ois = ois;
        this.oos = oos;
    }

    /// 用来接受客户端发过来的Message信息
    @Override
    public void run() {
        boolean loop = true;
        try {
//            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            while (loop) {
                System.out.println("服务端 等待 客户端( " + UserId + " )发送消息，读取中");
                /// 一直阻塞，直到用户发来消息，读取
                Message message = (Message) ois.readObject();
                /// 输出内容
//                System.out.println("用户 "+message.getSender() + " 发来消息 ：" + message.getContent());

                /// 如果消息类型是群发
                if (message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)) {
                    System.out.println("用户 " + message.getSender() + " 群发消息!");
                    /// 拿到发送者的线程对象，便于群发时区分自己，不发送给自己；
                    ServerConnectClientThread sender = ManageServerConnectClientThread.get(message.getSender());
                    /// 拿到线程集合中所有的用户对象，遍历拿到每个对象
                    Collection<ServerConnectClientThread> users = ManageServerConnectClientThread.getMap().values();
                    Iterator<ServerConnectClientThread> iterator = users.iterator();
                    while (iterator.hasNext()) {
                        /// 遍历拿到每个对象
                        ServerConnectClientThread user = iterator.next();
                        /// 如果不是发送者自己，就拿到该对象的输出流，并发送；
                        if (sender == user) continue;
                        ObjectOutputStream oos = user.oos;
                        oos.writeObject(message);
                        oos.flush();
                    }
                }

                /// 如果接收到的消息类型是 客户端退出
                if (message.getMesType().equals(MessageType.MESSAGE_CLIENT_EXIT)) {
                    System.out.println("用户 " + message.getSender() + " " + message.getContent());
                    /// 将此跟客户端通讯的线程退出；
                    loop = false;
                    /// 等客户端退出，等个100毫秒；
                    Thread.sleep(100);
                    oos.close();
                    ois.close();
                    socket.close();
                    /// 将此线程对象从集合中删除
                    ManageServerConnectClientThread.remove(message.getSender());
                }


                /// 如果发过来的消息类型是 GET_ONLINE_FRIEND（获取在线人数）
                if (message.getMesType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)) {
                    System.out.println("用户 " + message.getSender() + " " + message.getContent());
                    /// 返回在线用户
                    ReturnOnlineUsers(oos, message);
                }

                /**
                 * 如果接收到的消息类型是  普通消息 即 私聊
                 * 接收到后看看接收者ID是谁，是否在线，然后通过ID拿到对应的线程对象，再拿到输出流，并发送；
                 */
                if (message.getMesType().equals(MessageType.MESSAGE_COMM_MES)) {
                    /// 判断线程集合中是否存在接受方对应的线程对象，如果接收方没有与服务器连接通讯
                    if (ManageServerConnectClientThread.get(message.getGetter()) == null) {
                        Message returnMessage = new Message();
                        /// 在未链接通讯的基础上，如果用户不在用户集合中，表示接收方根本就没注册账号；
                        if (QQServer.getServerHashMap().get(message.getGetter()) == null) {
                            returnMessage.setMesType(MessageType.MESSAGE_USER_NOT_EXISTS);

                        } ///否则就是有账号，但未上线；就给他留言，暂时保存到key为接收方的集合中；与服务端连接时判断有没有人与他留言，有留言就发送；
                        else {
                            /// 将消息保存到离线消息集合；
                            ManageOfflineMessages.putMessage(message.getGetter(),message);
                            /// 将消息类型设置成用户不在线；返回
                            returnMessage.setMesType(MessageType.MESSAGE_USER_NOT_ONLINE);
                        }
                        /// 将用户状态反馈给发送方；
                        oos.writeObject(returnMessage);
                        oos.flush();
                        continue;
                    } else {
                        /// 如果接收方在线；
                        System.out.println("用户 " + message.getSender() + " 给 " + message.getGetter() + " 发送私聊");
                        String getter = message.getGetter();
                        /// 从线程集合中拿到线程对象，再拿到服务器跟接受方通讯的输出流，并发送；
                        ObjectOutputStream oos1 = ManageServerConnectClientThread.get(getter).oos;
                        oos1.writeObject(message);
                        oos1.flush();
                    }
                }

                if (message.getMesType().equals(MessageType.MESSAGE_FILE_MES)) {
                    /// 判断线程集合中是否存在接受方对应的线程对象，如果接收方没有与服务器连接通讯
                    if (ManageServerConnectClientThread.get(message.getGetter()) == null) {
                        /// 为了不影响保存到离线集合中的消息，新创建的消息对象
                        Message returnMessage = new Message();
                        /// 在未链接通讯的基础上，如果用户不在用户集合中，表示接收方根本就没注册账号；
                        if (QQServer.getServerHashMap().get(message.getGetter()) == null) {
                            returnMessage.setMesType(MessageType.MESSAGE_USER_NOT_EXISTS);

                        } ///否则就是有账号，但未上线；就给他留言，暂时保存到key为接收方的集合中；与服务端连接时判断有没有人与他留言，有留言就发送；
                        else {
                            /// 将消息保存到离线消息集合；
                            ManageOfflineMessages.putMessage(message.getGetter(), message);
                            /// 将消息类型设置成用户不在线；返回
                            returnMessage.setMesType(MessageType.MESSAGE_USER_NOT_ONLINE);
                        }
                        /// 将用户状态反馈给发送方；
                        oos.writeObject(returnMessage);
                        oos.flush();
                        continue;
                    }else {
                        /// 如果用户在线，正常发送；
                        ObjectOutputStream oos1 = ManageServerConnectClientThread.get(message.getGetter()).oos;
                        oos1.writeObject(message);
                        oos1.flush();
                    }
                }
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("客户端( " + UserId + " ) 断开连接");
    }

    public void ReturnOnlineUsers(ObjectOutputStream oos, Message message) throws IOException {
        /// 线程集合存放的格式是 HashMap<String , ServerConnectClientThread> map
        /// 每 有一个用户验证成功连接到后，都会存放到该集合，我们可以遍历key，获取UserID，拼接后返回
        Set<String> users = ManageServerConnectClientThread.getMap().keySet();
        /// 用来拼接的字符串
        StringBuilder str = new StringBuilder();
        /// 遍历
        Iterator<String> iterator = users.iterator();
        while (iterator.hasNext()) {
            /// 规定服务器返回时，中间空格，便于客户端分割处理；
            str.append(iterator.next()).append(" ");
        }
        /// 设置消息类型为 MESSAGE_RET_ONLINE_FRIEND 并返回 ， 客户端识别后自己处理；
        message.setMesType(MessageType.MESSAGE_RET_ONLINE_FRIEND);
        message.setContent(str.toString());
        oos.writeObject(message);
    }


}
